package ws

import (
	"fmt"
	"sync"

	"gitee.com/tinkler/yunfei/ws/arsenal"
	"gitee.com/tinkler/yunfei/ws/forge"
)

var (
	swordMu   sync.RWMutex
	swords    = make(map[string]arsenal.Sword)
	showSword = "wind"

	scabbardMu   sync.RWMutex
	scabbards    = make(map[string]arsenal.Scabbard)
	showScabbard = "wind"
)

// ForgeSword forge a sword named by name
func ForgeSword(name string, sword arsenal.Sword) {
	swordMu.Lock()
	defer swordMu.Unlock()
	if sword == nil {
		panic("ws: Forge sword is nil")
	}
	if _, dup := swords[name]; dup {
		panic("ws: Forge called twice for sword " + name)
	}
	swords[name] = sword
}

// ForgeScabbard forge a scabbard named by name for sword
func ForgeScabbard(name string, scabbard arsenal.Scabbard) {
	scabbardMu.Lock()
	defer scabbardMu.Unlock()
	if scabbard == nil {
		panic("ws: Forge scabbard is nil")
	}
	if _, dup := scabbards[name]; dup {
		panic("ws: Forge called twice for scabbard " + name)
	}
	scabbards[name] = scabbard
}

// SetShowSword the showing sword
func SetShowSword(name string) {
	swordMu.RLock()
	defer swordMu.RUnlock()
	if _, has := swords[name]; !has {
		panic(fmt.Sprintf("ws: Sword name %s is not forged\n", name))
	}
	showSword = name
}

// SetShowScabbard the showing scabbard
func SetShowScabbard(name string) {
	scabbardMu.RLock()
	defer scabbardMu.RUnlock()
	if _, has := scabbards[name]; !has {
		panic(fmt.Sprintf("ws: Scabbard name %s is not forged\n", name))
	}
	showScabbard = name
}

// TakeSwordFromYaml Take sword from yaml file
func TakeSwordFromYaml(name string, path string) *WS {
	var conf forge.YamlConf
	forge.UnmarshalYamlFile(path, &conf)

	//Sword forge
	s := getSword()
	s.Forge(conf)
	//Scabbard forge
	sheath := getScabbard().NewSheath(name, conf)

	WS := WS{config: conf, Response: forge.Response{}, Sheath: sheath}
	return &WS
}

func getSword() arsenal.Sword {
	swordMu.RLock()
	sword, ok := swords[showSword]
	swordMu.RUnlock()
	if !ok {
		panic("ws: unkown sword " + showSword)
	}
	return sword
}

func getScabbard() arsenal.Scabbard {
	scabbardMu.RLock()
	scabbard, ok := scabbards[showScabbard]
	scabbardMu.RUnlock()
	if !ok {
		panic("ws: unkown scabbard " + showScabbard)
	}
	return scabbard
}

// WS wind sword
type WS struct {
	config   forge.YamlConf
	Sheath   arsenal.Sheath
	Response forge.Response
}

// GetAuthKey get the auth key
func (w *WS) GetAuthKey() []byte {
	return w.config.AuthKey
}

// Logf debug log
func (w *WS) Logf(format string, a ...interface{}) {
	s := getSword()
	s.Logf(format, a...)
}

// Errorf error log
func (w *WS) Errorf(format string, a ...interface{}) {
	s := getSword()
	s.Errorf(format, a...)
}

// GetS get scabbard
func (w *WS) GetS() arsenal.Scabbard {
	return getScabbard()
}

// Error the ws error
type Error struct {
	Message string
}

func (err Error) Error() string {
	return "ws: " + err.Message
}
